﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Timers;

namespace ConnectionQualityIcon
{
    public class ConnectionMonitor
    {
        private Queue<double> history = new Queue<double>();
        private long latency;
        private long jitter;

        private Ping pingSender;
        private string hostname;
        private int timeout;
        private byte[] buffer;
        private PingOptions options;

        private Timer timer;

        public double Latency { get {
            return latency;
        } }
        public long Jitter { get {
            return jitter;
        } }

        public event PingCompletedEventHandler Update
        {
            add { pingSender.PingCompleted += value; }
            remove { pingSender.PingCompleted -= value; }
        }

        public ConnectionMonitor()
        {
            pingSender = new Ping();
            hostname = "8.8.8.8";
            timeout = 3000;
            buffer = Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

            options = new PingOptions() {
                DontFragment = true
            };

            pingSender.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback);
            BeginMonitoring();
        }

        private void BeginMonitoring()
        {
            pingSender.SendAsync(hostname, timeout, buffer, options);
            // Get first result.
            timer = new Timer(6000) { AutoReset = true };
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
            // Set up a timer to get a new ping result every 6 seconds.
        }

        private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
        {
            PingReply reply = e.Reply;
            if (reply.Status == IPStatus.Success)
            {
                history.Enqueue(reply.RoundtripTime);
            }
            else
            {
                history.Enqueue(999);
            }

            if (history.Count > 10) { history.Dequeue(); }

            double avg = history.Average();
            double sum = history.Sum(d => (d - avg) * (d - avg));
            double sd = Math.Sqrt(sum / history.Count);

            latency = (long)Math.Round(avg);
            jitter = (long)Math.Round(sd);
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            pingSender.SendAsync(hostname, timeout, buffer, options);
        }
    }
}
